#TODO
#check performance tips
#look for bottlenecks
#
from config import *
from dataloader import *
from drawing import *
from networklayers import *
from neuron import *

class Network:
	def __init__(self, cfg):
		self.cfg = cfg
		self.nl = NetworkLayers(cfg)
		self.dl = DataLoader(cfg)
		self.draw = Drawing(cfg)
		self.output_labels = []
		self.result = {}
		self.counter = 0

		self.draw.clean_folder()

		if cfg.verbose:	self.cfg.log(cfg.architecture_to_str())

		#debug
		if cfg.debug: cfg.log(self.nl.terminals_to_str())

	def train(self):
		#making aliases
		dl = self.dl;nl = self.nl;cfg = self.cfg;log = self.cfg.log

		#getting data
		training_set = dl.get_training_set(self.cfg.training_set_size)
		if 0:
			i = training_set[1].index('Iris-virginica')
			a = training_set[0][i]
			al = training_set[1][i]
			i = training_set[1].index('Iris-setosa')
			b = training_set[0][i]
			bl = training_set[1][i]
			i = training_set[1].index('Iris-versicolor')
			c = training_set[0][i]
			cl = training_set[1][i]
			training_set = ([],[])
			for x in xrange(10):
				training_set[0].append(a)
				training_set[1].append(al)
			#for x in xrange(20):
				training_set[0].append(b)
				training_set[1].append(bl)
			#for x in xrange(20):
				training_set[0].append(c)
				training_set[1].append(cl)
			print a,al
			print b,bl
			print c,cl
			self.ts = training_set
		for xc in xrange(1):
			if xc: self.cfg.new = False
			#print xc
			for pattern_number, pattern in enumerate(map(dl.encode_pattern, training_set[0])):
				#debug
				if cfg.debug: log('pattern %3d :: %s' % (pattern_number, map(lambda x: '%1.3f' % x, pattern)), 2)

				#reseting network
				nl.apply('reset')

				#adding spiking pattern to the input layer
				nl.present(pattern)

				#if self.cfg.allow_imaging_heavy: self.draw.draw_epsilons(self.nl.output_layer)

				#prpogating with training
				nl.propogate(True)

				if cfg.verbose:
					self.counter += 1
					cfg.percentage(self.counter)

			if self.cfg.allow_imaging: self.draw.draw_network(self.nl, pattern, self.counter)
			if self.cfg.allow_imaging_heavy: self.draw.draw_epsilons(self.nl.output_layer)


	def test(self):
		#making aliases
		dl = self.dl;nl = self.nl;cfg = self.cfg;log = self.cfg.log

		test_set = self.dl.get_training_set(self.cfg.test_set_size)
		#test_set = self.ts

		for pattern_number, pattern in enumerate(map(dl.encode_pattern, test_set[0])):

			#reseting network
			nl.apply('reset')

			#adding spiking pattern to the input layer
			nl.present(pattern)

			#propogating
			key = nl.propogate(False)
			#print pattern_number,key
			#debug
			if cfg.debug: log('%d %s %s classificated as %s' % (pattern_number, map(lambda x: '%1.3f' % x, pattern),test_set[1][pattern_number],key),2)

			self.output_labels.append(key)
			if not self.result.has_key(key):
					self.result[key] = []
			self.result[key].append(test_set[1][pattern_number])

			if cfg.verbose:
				self.counter += 1
				cfg.percentage(self.counter)

		#processing results
		alias = {}
		for k in self.result.keys():
			amount = 0
			labels = self.result[k]
			while labels:
				if labels.count(labels[0]) > amount:
					alias[labels[0]] = k
					amount = labels.count(labels[0])
				labels = [x for x in labels if x != labels[0]]

		#imaging
		if self.cfg.allow_imaging_final:
			self.draw.draw_data(map(dl.encode_pattern, test_set[0]), test_set[1], self.output_labels, alias)

	def report(self, verbose):
		hr = {}
		hrc = 0

		out = '\r'
		for k in self.result.keys():
			hr[k] = {}
			out += '\n' + str(k) + ' = > '
			labels = self.result[k]
			while labels:
				out += labels[0] + '(' + str(labels.count(labels[0])) + ') '
				hr[k][labels[0]] = labels.count(labels[0])
				hrc += 1
				labels = [x for x in labels if x != labels[0]]

		if self.cfg.verbose:
			self.cfg.log(str(self.nl), 2)
			self.cfg.log(self.nl.terminals_to_str())

		#debug
		sum = 0
		for k in hr.keys():
			if k != None:
				max = 0
				max_k = None
				for v in hr[k].keys():
					if hr[k][v] > max :
						max = hr[k][v]
						max_k = v
				for k2 in hr.keys():
					for v2 in hr[k2].keys():
						if v2 == max_k:
							hr[k2][v2] = 0
				sum += max
		result = sum * 1.0 / self.cfg.test_set_size
		if result > 0.95:
			out += '\n\n%1.3f UA' % result
		else:
			out += '\n\n!%1.3f\n' % result

		if len(hr.keys()) == 3 and (not hr.has_key(None)) and hrc in  [3,4,5]:
			self.cfg.log(out)
			self.cfg.log(str(self.cfg))

		print out
		#print str(self.cfg)
